package com.dingding.dao.basedao.impl;

import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.springframework.orm.hibernate4.HibernateTemplate;

import com.dingding.common.core.util.ToolUtil;
import com.dingding.dao.basedao.IBaseDao;

/**
 * 
 * @ClassName: BaseDaoImpl
 * @Description:dao公共实现类，所有dao继承此类。当前类的所有异常监控放在service完成
 * @author cheshaowei
 * @date 2015-7-3 下午03:35:14
 * @version 叮叮搭车V2.0
 * 
 */
@SuppressWarnings("all")
public abstract class BaseDaoImpl<T> implements IBaseDao<T> {

	protected Logger log = Logger.getLogger(this.getClass());

	private Class<T> clazz = null;
	private final String QUERY_HQL = " FROM " + this.getGenericType().getName()
			+ " as obj ";

	private HibernateTemplate template = null;

	/**
	 * @Title: getGentricType
	 * @Description: 获取参数类型
	 * @return Class<T> 通过参数类型获取到的对象类型
	 * @throws
	 */
	public Class<T> getGenericType() {
		if (this.clazz == null) {
			this.clazz = (Class<T>) ((ParameterizedType) getClass()
					.getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return clazz;
	}

	/**
	 * 
	 * @Title: getQuery
	 * @Description: 获取Query
	 * @param hql
	 * @return Query
	 * @throws
	 */
	protected Query getQuery(String hql) {
		return this.getSession().createQuery(hql);
	}

	/**
	 * 
	 * @Title: getSession
	 * @Description: 获取session
	 * @return Session
	 * @throws
	 * 
	 */
	public Session getSession() {
		return template.getSessionFactory().getCurrentSession();
	}

	/**
	 * 
	 * @Title: getById
	 * @Description: 根据ID获取实体对象
	 * @param id
	 *            主键ID
	 * @param isCache
	 *            是否使用查询缓存 true:是 false：不是
	 * @return T
	 * @throws
	 * 
	 */
	@Override
	public T getById(String id, boolean isCache) {
		T t = this.getTemplate().get(this.getGenericType(), id);
		return t;
	}

	/**
	 * 
	 * @Title: getById
	 * @Description: 根据ID获取实体对象
	 * @param id
	 *            主键ID
	 * @param isCache
	 *            是否使用查询缓存 true:是 false：不是
	 * @return T
	 * @throws
	 * 
	 */
	@Override
	public T getById(Integer id, boolean isCache) {
		T t = this.getTemplate().get(this.getGenericType(), id);
		return t;
	}

	/**
	 * 
	 * @Title: saveOrUpdate
	 * @Description: 保存或更新一个hibernate对象
	 * @param t
	 * @return void
	 * @throws
	 * 
	 */
	@Override
	public void saveOrUpdate(T t) {
		this.getTemplate().saveOrUpdate(t);
	}

	/**
	 * 
	 * @Title: save
	 * @Description:保存一个对象
	 * @author cheshaowei
	 * @throws
	 */
	@Override
	public void save(T t) {
		this.getTemplate().save(t);
	}

	/**
	 * 
	 * @Title: update
	 * @Description: 更新
	 * @param 待保存的对象
	 * @return void
	 * @throws
	 * 
	 */
	@Override
	public void update(T t) {
		this.getTemplate().update(t);
	}

	/**
	 * 
	 * @Title: delete
	 * @Description: 删除一个hibernate对象
	 * @param t
	 * @return void
	 * @throws
	 * 
	 */
	@Override
	public void delete(T t) {
		this.getTemplate().delete(t);
	}

	/**
	 * 
	 * @Title: deleteRow
	 * @Description: 根据ID删除数据，并返回受影响行数
	 * @param hql
	 * @param id
	 *            主键ID
	 * @return int 受影响行数
	 * @throws
	 */
	@Override
	public int deleteRow(String hql, String id) {
		Query query = this.getSession().createQuery(hql);
		int row = query.executeUpdate();
		return row;
	}

	/**
	 * 
	 * @Title: queryAll
	 * @Description: 查询表中所有数据对象
	 * @param isCache
	 *            是否使用缓存 true：使用 false： 不使用
	 * @return List<T> 查询到的数据集合
	 * @throws
	 * 
	 */
	@Override
	public List<T> queryAll(boolean isCache) {
		Query query = this.getSession().createQuery(this.QUERY_HQL);
		// 设置查询缓存
		if (isCache) {
			query.setCacheable(true);
		}
		List<T> list = query.list();
		return list;
	}

	/**
	 * 
	 * @Title: queryCriteriaList
	 * @Description: 根据条件查询数据
	 * @param criterion
	 *            查询条件
	 * @param isCache
	 *            是否使用查询缓存 true:使用 false：不使用
	 * @return List<T> 查询到的数据集合
	 * @author cheshaowei
	 * @throws
	 */
	@Override
	public List<T> queryCriteriaList(Criterion criterion, boolean isCache) {
		Criteria criteria = this.getSession().createCriteria(
				this.getGenericType());
		if (isCache) {
			criteria.setCacheable(true);
		}
		List<T> list = criteria.add(criterion).list();
		return list;
	}

	/**
	 * 
	 * @Title: listHqlUnResult
	 * @Description: 根据条件查询唯一对象
	 * @param criteria
	 *            查询条件
	 * @return T
	 * @throws
	 */
	@Override
	public T queryCriteriaUnResult(Criterion criterion, boolean isCache) {
		Criteria criteria = this.getSession().createCriteria(
				this.getGenericType());
		if (isCache) {
			criteria.setCacheable(true);
		}
		T t = (T) criteria.add(criterion).uniqueResult();
		return t;
	}

	/**
	 * 
	 * @Title: listHql
	 * @Description: Hql带参查询
	 * @param Hql
	 *            自定义Hql
	 * @param parm
	 *            参数值
	 * @return List<T> 查询到的数据集合
	 * @throws
	 * 
	 */
	@Override
	public List<T> listHql(String Hql, boolean isCache, Object... parm) {

		Query query = this.getQuery(Hql);

		if (isCache) {
			query.setCacheable(true);
		}

		if (ToolUtil.isNotNullObj(parm)) {
			setParameters(query, parm); // 设置hql参数
		}

		List<T> list = query.list();

		return list;
	}

	/**
	 * 
	 * @Title: hqlQueryListByPage
	 * @Description: Hql带参分页查询
	 * @param Hql
	 *            自定义Hql
	 * @param currentPage
	 *            当前页
	 * @param pageSize
	 *            每页显示记录数
	 * @param parm
	 *            参数值
	 * @return List<T> 查询到的数据集合
	 * @throws
	 * 
	 */
	@Override
	public List<T> hqlQueryListByPage(String Hql, int currentPage,
			int pageSize, boolean isCache, Object... parm) {

		Query query = this.getQuery(Hql);

		if (isCache) {
			query.setCacheable(true);
		}

		if (ToolUtil.isNotNullObj(parm)) {
			setParameters(query, parm); // 设置hql参数
		}

		if (pageSize != 0) {
			query.setMaxResults(pageSize); // 每页查询多少条记录
			query.setFirstResult((currentPage - 1) * pageSize); // 从第几条记录开始查询
		}

		List<T> list = query.list();

		return list;
	}

	/**
	 * 
	 * @Title: listSqlObj
	 * @Description: 原生sql查询
	 * @param sql
	 * @param currentPage
	 *            当前页
	 * @param pageSize
	 *            每页显示记录数
	 * @param parm
	 * @return List<Object[]> 查询到的数据集合
	 * @throws
	 */
	@Override
	public List<Object[]> sqlQueryListObj(String sql, boolean isCache,
			Object... parm) {

		SQLQuery query = this.getSQlQuery(sql);

		if (isCache) {
			query.setCacheable(true);
		}

		if (ToolUtil.isNotNullObj(parm)) {
			setParameters(query, parm); // 设置sql参数
		}
		List<Object[]> list = query.list();
		return list;
	}

	/**
	 * 
	 * @Title: sqlQueryUnResultObj
	 * @Description: 原生sql查询
	 * @param sql
	 *            原生sql
	 * @param isCache
	 *            是否使用缓存
	 * @param parm
	 *            查询条件
	 * @return Object[] 查询到的单个数据
	 * @throws
	 */
	@Override
	public Object[] sqlQueryUnResultObj(String sql, boolean isCache,
			Object... parm) {

		SQLQuery sqlQuery = this.getSQlQuery(sql);

		if (isCache) {
			sqlQuery.setCacheable(true);
		}

		if (ToolUtil.isNotNullObj(parm)) {
			setParameters(sqlQuery, parm); // 设置sql参数
		}
		
		List<Object[]> objects = sqlQuery.list();
        
		Object[] obj = null;
		if(objects != null && objects.size()>0){
			obj = objects.get(0);
		}
		
		return obj;
	}

	/**
	 * @Title: queryCriteriaListByPage
	 * @Description: 根据条件查询数据,带分页
	 * @param criterion
	 *            查询条件
	 * @param isCache
	 *            是否使用查询缓存 true:使用 false：不使用
	 * @return List<T> 查询到的数据集合
	 * @author cheshaowei
	 * @throws
	 */
	@Override
	public List<T> queryCriteriaListByPage(Criterion criterion,String order,
			int currentPage, int pageSize, boolean isCache) {

		Criteria criteria = this.getSession().createCriteria(
				this.getGenericType());
		
		criteria.addOrder(Order.desc(order));

		if (isCache) {
			criteria.setCacheable(true);
		}

		if (pageSize != 0) {
			criteria.setMaxResults(pageSize); // 每页查询多少条记录
			criteria.setFirstResult((currentPage - 1) * pageSize); // 从第几条记录开始查询
		}

		List<T> list = criteria.add(criterion).list();

		return list;

	}

	/**
     * @Title: updateSqlRow 
     * @Description: 执行修改SQL语句
     * @param sql 拼接SQL
     * @param parm 不定参
     * @return int    返回类型 
     * @throws
     */
	@Override
	public int updateSqlRow(String sql, Object... parm) {
		int row = 0;
		try {
			SQLQuery query = this.getSQlQuery(sql);
			if (ToolUtil.isNotNullObj(parm)) {
				setParameters(query, parm);
			}
			row = query.executeUpdate();
		} catch (Exception e) {
			log.error("修改Hibernate对象出现异常！类：" + this.getClass() + " line:187", e);
		}
		return row;
	}
	
	/**
	 * 
	 * @Title: setParameters
	 * @Description: 设置参数
	 * @param
	 * @return void
	 * @throws
	 * 
	 */
	protected void setParameters(Query query, Object[] parmas) {
		if (query.getQueryString().indexOf("?") == -1) {
			return;
		}
		for (int i = 0; i < parmas.length; i++) {
			if (parmas[i] instanceof Date) {
				query.setParameter(i, (Date) parmas[i]);
			} else {
				query.setParameter(i, parmas[i]);
			}
		}
	}

	/**
	 * 
	 * @Title: getQuery
	 * @Description: 获取SQlQuery
	 * @param @param hql
	 * @param @return
	 * @return Query
	 * @throws
	 */
	protected SQLQuery getSQlQuery(String hql) {
		return this.getSession().createSQLQuery(hql);
	}
	
	/**
     * 
     * @Title: queryCriteriaList 
     * @Description: 根据条件查询数据
     * @param criterion 查询条件
     * @param isCache 是否使用查询缓存 true:使用 false：不使用
     * @return List<T> 查询到的数据集合
     * @throws
     */
	@Override
	public List<T> queryCriteriaListByOrderDesc(Criterion criterion,String orderString,boolean isCache){
		Criteria criteria = this.getSession().createCriteria(
				this.getGenericType());
		
		criteria.addOrder(Order.desc(orderString));
		
		if (isCache) {
			criteria.setCacheable(true);
		}
		List<T> list = criteria.add(criterion).list();
		return list;
	}

	public HibernateTemplate getTemplate() {
		return template;
	}

	public void setTemplate(HibernateTemplate template) {
		this.template = template;
	}

	@Override
	public int addNativeSQLRow(String sql, Object... parm) {
		int row = 0;
		try {
			SQLQuery query = this.getSQlQuery(sql);
			if (ToolUtil.isNotNullObj(parm)) {
				setParameters(query, parm);
			}
			row = query.executeUpdate();
		} catch (Exception e) {
			log.error("添加Hibernate对象出现异常！类：" + this.getClass() + "line:200", e);
		}
		return row;
	}
	
}
